/*
 *    Copyright (c) 2018-2025, lengleng All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the pig4cloud.com developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: lengleng (wangiegie@gmail.com)
 */

package com.pig4cloud.pigx.order.controller;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.common.core.util.wechat.PayUtil;
import com.pig4cloud.pigx.common.core.util.wechat.WechatUtils;
import com.pig4cloud.pigx.common.log.annotation.SysLog;
import com.pig4cloud.pigx.common.security.annotation.Inner;
import com.pig4cloud.pigx.common.security.util.SecurityUtils;
import com.pig4cloud.pigx.order.api.dto.OrderInfoDTO;
import com.pig4cloud.pigx.order.api.entity.OrderInfo;
import com.pig4cloud.pigx.order.api.vo.OrderInfoVO;
import com.pig4cloud.pigx.order.service.OrderInfoService;
import com.pig4cloud.pigx.shop.user.api.dto.CustomToUserOrderSummaryDTO;
import com.pig4cloud.pigx.shop.user.api.vo.CustomToUserOrderSummaryVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.access.prepost.PreAuthorize;
import com.pig4cloud.pigx.common.excel.annotation.ResponseExcel;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import org.springframework.http.HttpHeaders;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.List;
import java.util.Map;

/**
 * 订单管理
 *
 * @author pigx code generator
 * @date 2023-12-06 22:47:34
 */
@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/order")
@Tag(description = "order", name = "订单管理管理")
@SecurityRequirement(name = HttpHeaders.AUTHORIZATION)
public class OrderInfoController {

	private final OrderInfoService orderService;

	private final RedisTemplate redisTemplate;

	/**
	 * 分页查询
	 * @param page 分页对象
	 * @param orderInfo 订单管理
	 * @return
	 */
	@Operation(summary = "分页查询", description = "分页查询")
	@GetMapping("/page")
	public R getOrderPage(Page page, OrderInfo orderInfo) {
		// return R.ok(orderService.page(page, Wrappers.query(order)));
		return R.ok(orderService.getOrderPageList(page, orderInfo));
	}

	/**
	 * 通过id查询订单管理
	 * @param orderId id
	 * @return R
	 */
	@Operation(summary = "通过id查询", description = "通过id查询")
	@GetMapping("/{orderId}")
	public R getById(@PathVariable("orderId") Long orderId) {
		return R.ok(orderService.getOrderInfoByOrderId(orderId));
	}

	/**
	 * 新增订单管理
	 * @param order 订单管理
	 * @return R
	 */
	@Operation(summary = "新增订单管理", description = "新增订单管理")
	@SysLog("新增订单管理")
	@PostMapping
	@PreAuthorize("@pms.hasPermission('shop_order_add')")
	public R save(@RequestBody OrderInfo order) {
		return R.ok(orderService.save(order));
	}

	/**
	 * 修改订单管理
	 * @param order 订单管理
	 * @return R
	 */
	@Operation(summary = "修改订单管理", description = "修改订单管理")
	@SysLog("修改订单管理")
	@PutMapping
	@PreAuthorize("@pms.hasPermission('shop_order_edit')")
	public R updateById(@RequestBody OrderInfo order) {
		return R.ok(orderService.updateById(order));
	}

	/**
	 * 通过id删除订单管理
	 * @param orderId id
	 * @return R
	 */
	@Operation(summary = "通过id删除订单管理", description = "通过id删除订单管理")
	@SysLog("通过id删除订单管理")
	@DeleteMapping("/{orderId}")
	@PreAuthorize("@pms.hasPermission('shop_order_del')")
	public R removeById(@PathVariable Long orderId) {
		return R.ok(orderService.removeById(orderId));
	}

	/**
	 * 导出excel 表格
	 * @param order 查询条件
	 * @return excel 文件流
	 */
	@ResponseExcel
	@GetMapping("/export")
	@PreAuthorize("@pms.hasPermission('shop_order_export')")
	public List<OrderInfo> export(OrderInfo order) {
		return orderService.list(Wrappers.query(order));
	}

	/**
	 * c端创建订单
	 * @return
	 */
	@PostMapping("/c/create")
	public R create(@RequestBody OrderInfoVO orderVO) {
		Long shopUserId = SecurityUtils.getUser().getId();
		orderVO.setShopUserId(shopUserId);
		return orderService.create(orderVO);
	}

	/**
	 * 通过订单ID获取订单详情
	 * @param orderId
	 * @return
	 */
	@GetMapping("/c/orderInfo/{orderId}")
	public R getOrderInfo(@PathVariable(value = "orderId") Long orderId) {
		Long shopUserId = SecurityUtils.getUser().getId();
		return orderService.getOrderInfo(shopUserId, orderId);
	}

	/**
	 * c端分页获取订单列表
	 * @return
	 */
	@GetMapping("/c/order/page")
	public R getOrderPageList(Page page, OrderInfo orderInfo) {
		Long shopUserId = SecurityUtils.getUser().getId();
		orderInfo.setShopUserId(shopUserId);
		return R.ok(orderService.getOrderPageList(page, orderInfo));
	}

	/**
	 * 订单支付成功回调
	 * @return
	 */
	@PostMapping("/pay/successed")
	public R orderPaySuccess(@RequestBody OrderInfo orderInfo) {
		return R.ok(orderService.orderPaySuccess(orderInfo));
	}

	/**
	 * 订单签收
	 * @return
	 */
	@PostMapping("/c/orderSingFor")
	public R orderSingFor(@RequestBody OrderInfo orderInfo) {
		Long shopUserId = SecurityUtils.getUser().getId();
		orderInfo.setShopUserId(shopUserId);
		return orderService.orderSingFor(orderInfo);
	}

	/**
	 * 订单退款
	 * @return
	 */
	@PostMapping("/orderRefund")
	public R orderRefund(@RequestBody OrderInfo orderInfo) {
		return orderService.orderRefund(orderInfo);
	}

	/**
	 * 取消订单
	 * @param orderInfo
	 * @return
	 */
	@PostMapping("/c/cancel")
	public R orderCancel(@RequestBody OrderInfo orderInfo) {
		return orderService.orderCancel(orderInfo);
	}

	/**
	 * 订单退货
	 * @return
	 */
	@PostMapping("/orderReturn")
	public R orderReturn(@RequestBody OrderInfo orderInfo) {
		return orderService.orderReturn(orderInfo);
	}

	/**
	 * 微信小程序支付
	 * @return
	 */
	@PostMapping("/c/wechatPay")
	public R wechatPay(@RequestBody OrderInfoDTO orderInfo) throws Exception {
		log.info("进入支付方法");
		String orderId = orderInfo.getId().toString();
		Integer money = Integer.parseInt(orderInfo.getOrderPrice().toString());
		String openId = orderInfo.getOpenId();
		Map<String, String> resMap = WechatUtils.xcxPayment(orderId, money, openId);
		if ("SUCCESS".equals(resMap.get("returnCode")) && "OK".equals(resMap.get("returnMsg"))) {
			// 统一下单成功
			resMap.remove("returnCode");
			resMap.remove("returnMsg");
			// 保存当前支付信息
			OrderInfo order = new OrderInfo();
			order.setId(orderInfo.getId());
			order.setWechatPayInfo(JSON.toJSONString(resMap));
			orderService.updateById(order);
			log.info("【小程序支付服务】支付下单成功！");
			return R.ok(resMap);
		}
		else {
			log.info("【小程序支付服务】支付下单失败！原因:" + resMap.get("returnMsg"));
			return R.failed(resMap.get("returnMsg"));
		}
	}

	@Inner(false)
	@RequestMapping("/wechat/pay/callback")
	public String wechatPayCallback(HttpServletRequest request, HttpServletResponse response) throws Exception {
		InputStream inputStream = request.getInputStream();
		// 获取请求输入流
		ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
		byte[] buffer = new byte[1024];
		int len = 0;
		while ((len = inputStream.read(buffer)) != -1) {
			outputStream.write(buffer, 0, len);
		}
		outputStream.close();
		inputStream.close();
		Map<String, Object> map = PayUtil.getMapFromXML(new String(outputStream.toByteArray(), "utf-8"));
		log.info("【小程序支付回调】 回调数据： \n" + map);

		String orderNo = (String) map.get("out_trade_no");
		Integer payPrice = Integer.parseInt(map.get("total_fee").toString());
		String orderNoKey = "shop_order_" + orderNo;
		Object o = redisTemplate.opsForValue().get(orderNoKey);
		if (o == null) {
			log.info("缓存不存在:" + orderNo + ",可能已经处理");
			// redisTemplate.opsForValue().set(orderNo, orderNo);
			// log.info("添加缓存:" + orderNo);

			return "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
					+ "<return_msg><![CDATA[OK]]></return_msg>" + "</xml>";
		}
		else {
			log.info("缓存已存在, 准备处理" + orderNoKey);
			redisTemplate.delete(orderNoKey);
			log.info("处理前先删除:" + orderNoKey);
		}

		String resXml = "";
		String returnCode = (String) map.get("return_code");
		if ("SUCCESS".equalsIgnoreCase(returnCode)) {
			String returnmsg = (String) map.get("result_code");
			if ("SUCCESS".equals(returnmsg)) {
				// 更新数据
				OrderInfo orderInfo = new OrderInfo();
				orderInfo.setId(Long.parseLong(orderNo));
				orderInfo.setPayPrice(payPrice);
				orderService.orderPaySuccess(orderInfo);
				log.info("支付成功:" + orderNo);
				// 支付成功
				resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
						+ "<return_msg><![CDATA[OK]]></return_msg>" + "</xml>";
			}
			else {
				resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
						+ "<return_msg><![CDATA[报文为空]></return_msg>" + "</xml>";
				log.info("支付失败:" + resXml);
			}
		}
		else {
			resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
					+ "<return_msg><![CDATA[报文为空]></return_msg>" + "</xml>";
			log.info("【订单支付失败】");
		}

		log.info("【小程序支付回调响应】 响应内容：\n" + resXml);
		return resXml;
	}

	/**
	 * 继续支付
	 * @return
	 */
	@PostMapping("/c/rePay")
	public R rePay(@RequestBody OrderInfoDTO orderInfo) {
		return orderService.rePay(orderInfo);
	}

	@Inner(false)
	@GetMapping("/sendMq")
	public R sendMq() {
		return R.ok(orderService.sendMq());
	}

	/**
	 * 根据用户获取订单信息
	 * @param customToUserOrderSummaryDTO
	 * @return
	 */
	@Inner
	@PostMapping("/getCustomToUserOrderSummary")
	public List<CustomToUserOrderSummaryVO> getCustomToUserOrderSummary(
			@RequestBody CustomToUserOrderSummaryDTO customToUserOrderSummaryDTO) {
		return orderService.getCustomToUserOrderSummary(customToUserOrderSummaryDTO);
	}

	public static void main(String[] args) throws Exception {
		WechatUtils.xcxPayment("111", 1, "222");
	}

}
